#include "image_filter_worker.h"

using namespace facebeauty;

namespace {

bool ConvertRgbToYuv(const QImage &img, FaceBeautyFrame& frame)
{
    frame.color_ = FACE_BEAUTY_COLOR_SPACE_YUV_I420_PLANAR;
    frame.width_ = img.width();
    frame.height_ = img.height();

    int in_frame_area = frame.height_ * frame.width_;

    frame.data_[0] = new uint8_t[in_frame_area];
    frame.data_[1] = new uint8_t[in_frame_area/4];
    frame.data_[2] = new uint8_t[in_frame_area/4];

    frame.stride_[0] = img.width();
    frame.stride_[1] = img.width() / 2;
    frame.stride_[2] = img.width() / 2;

    int pos = 0;
    int pos_uv = 0;
    int Y, U, V;
    for(int h = 0; h < frame.height_; h++) {
        for(int w = 0; w < frame.width_; w++) {
            pos = h * frame.width_ + w;

            auto pixel = img.pixelColor(w, h);
            Y = ((66 * pixel.red() + 129 * pixel.green() + 25 * pixel.blue() + 128) >> 8) + 16;
            U = ((-38 * pixel.red() - 74 * pixel.green() + 112 * pixel.blue() + 128) >> 8) + 128;
            V = ((112 * pixel.red() - 94 * pixel.green() - 18 * pixel.blue() + 128) >> 8) + 128;

            frame.data_[0][pos] = uint8_t(Y < 0 ? 0 : (Y > 255? 255: Y));

            if((w % 2 == 0) && (h % 2 == 0)) {
                pos_uv = (h/2) * (frame.width_/2) + (w/2);

                frame.data_[1][pos_uv] = uint8_t(U < 0 ? 0 : (U > 255? 255: U));
                frame.data_[2][pos_uv] = uint8_t(V < 0 ? 0 : (V > 255? 255: V));
            }
        }
    }

    return true;
}

bool ConvertYuvToRgb(FaceBeautyFrame& frame, QImage &img)
{

    int pos = 0;
    int pos_uv = 0;
    int R, G, B;
    int Y, U, V;
    QColor color;

    for(int h = 0; h < frame.height_; h++) {
        for(int w = 0; w < frame.width_; w++) {
            pos = h * frame.width_ + w;
            pos_uv = (h/2) * (frame.width_/2) + (w/2);

            Y = frame.data_[0][pos];
            U = frame.data_[1][pos_uv];
            V = frame.data_[2][pos_uv];

            R = Y + ((360 * (V - 128)) >> 8);
            G = Y - (((88 * (U - 128)  + 184 * (V - 128))) >> 8);
            B = Y + ((455 * (U - 128)) >> 8);

            color.setRed((R < 0 ? 0 : (R > 255 ? 255 : R)));
            color.setGreen((G < 0 ? 0 : (G > 255 ? 255 : G)));
            color.setBlue((B < 0 ? 0 : (B > 255 ? 255 : B)));

            img.setPixelColor(w, h, color);
        }
    }

    delete[] frame.data_[0];
    delete[] frame.data_[1];
    delete[] frame.data_[2];

    return true;
}

};

ImageFilterWorker::ImageFilterWorker(): images_(500)
{
    CreateFaceBeautyModule(filter_);
}

ImageFilterWorker::~ImageFilterWorker()
{

}

int ImageFilterWorker::ProccessFrame(QImage *frame)
{
    images_.Push(frame);

    return 0;
}

void ImageFilterWorker::run()
{
    QImage* img = nullptr;

    while(isRunning()) {
        if(images_.Empty()) {
            QThread::msleep(10);
            continue;
        }

        images_.Pop(img);
//        img->toPixelFormat(QImage::Format_RGB32);

//        struct FaceBeautyFrame frame;
//        ConvertRgbToYuv(*img, frame);
//        filter_->ProccessFrame(&frame);
//        ConvertYuvToRgb(frame, *img);

        output_handler_->ProccessFrame(img);
    }

}

int ImageFilterWorker::InitHandler(ImageHandler *handler)
{
    output_handler_ = handler;
    return 0;
}

int ImageFilterWorker::InitModule(int feature, size_t width, size_t height, facebeauty::FACE_BEAUTY_COLOR_SPACE color)
{
    return filter_->InitModule(feature, width, height, color);
}

int ImageFilterWorker::SetFeatureQuality(int feature, int quality)
{
    return filter_->SetFeatureQuality(feature, quality);
}

int ImageFilterWorker::Reset()
{
    filter_->Reset();
    images_.Clear();
    return 0;
}

